#include "os_sal.h"

#if (CONFIG_OS_ENABLE)

#if defined(CONFIG_OS_TYPE_FREERTOS)
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"
#include "event_groups.h"
#elif defined(CONFIG_OS_TYPE_UCOSII)
#error "CONFIG_OS_TYPE_UCOSII not support!"
#else
#error "CONFIG_OS_TYPE not support!"
#endif

/* 自定义堆栈缓存 */
#if (configAPPLICATION_ALLOCATED_HEAP == 1)
#if defined(STM32F407xx)
// FreeRTOS堆栈位于CCM
uint8_t ucHeap[60 * 1024] __AT_CCM(0x10000000);
#else
// FreeRTOS堆栈
uint8_t ucHeap[configTOTAL_HEAP_SIZE];
#endif
#endif

/* export func */

//开启任务调度
void os_scheduler_start(void)
{
    vTaskStartScheduler(); //开启任务调度
}

//关闭任务调度
void os_scheduler_end(void)
{
    vTaskEndScheduler();
}

//进入临界区
void os_critical_enter(void)
{
    taskENTER_CRITICAL(); //进入临界区
}

//退出临界区
void os_critical_exit(void)
{
    taskEXIT_CRITICAL(); //退出临界区
}

/**
 * @brief OS延时周期时间
 *
 * @param ticks 节拍数
 */
void os_delay(uint32_t ticks)
{
    vTaskDelay(ticks);
}

/**
 * @brief OS延时毫秒
 *
 * @param ms 毫秒
 */
void os_delay_ms(uint32_t ms)
{
    uint32_t ticks;

    ticks = (ms * configTICK_RATE_HZ) / 1000;
    ticks += (((ms * configTICK_RATE_HZ) % 1000) + 999) / 1000;

    vTaskDelay(ticks);
}

/**
 * @brief OS绝对延时
 *
 * @param ticks 节拍数
 */
void os_delay_unit(uint32_t ticks)
{
    static TickType_t tick_count = 0; //当前时钟节拍

    if (tick_count == 0)
    {
        tick_count = xTaskGetTickCount();
    }
    vTaskDelayUntil(&tick_count, ticks);
}

/**
 * @brief 获取系统名称
 * 
 * @return const char* 
 */
const char *os_get_name(void)
{
#if (CONFIG_OS_TYPE_FREERTOS)
	return "FreeRTOS";
#elif (CONFIG_OS_TYPE_UCOSII)
	return "uC/OS-II";
#elif (CONFIG_OS_TYPE_UCOSIII)
	return "uC/OS-III";
#elif (CONFIG_OS_TYPE_THREADX)
	return "Threadx";
#else
	return "unkonw";
#endif
}

/**
 * @brief 获取系统版本号
 *
 * @return const char*
 */
const char *os_get_version(void)
{
    return tskKERNEL_VERSION_NUMBER;
}

/**
 * @brief 获取系统栈总空间
 *
 * @return uint32_t
 */
uint32_t os_get_heap_total_size(void)
{
    return configTOTAL_HEAP_SIZE;
}

/**
 * @brief 获取系统剩余栈空间
 *
 * @return uint32_t
 */
uint32_t os_get_heap_free_size(void)
{
    return xPortGetFreeHeapSize();
}

extern void xPortSysTickHandler(void);
void os_systick_handler(void)
{
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) /* OS开始跑了,才执行正常的调度处理 */
    {
        xPortSysTickHandler();
    }
}


void *os_mem_malloc(uint32_t size)
{
    return pvPortMalloc(size);
}

void os_mem_free(void *ptr)
{
    vPortFree(ptr);
}


#if 0

//获取当前任务总数
uint32_t os_get_task_nums(void)
{
    return (uxTaskGetNumberOfTasks() - 1);
}


//获取所有任务状态
os_status_t os_get_task_status(os_task_status_t **task_sta)
{
#if (configUSE_STATS_FORMATTING_FUNCTIONS > 0)
	
	os_critical_enter();			//进入临界区
	{	
		TaskStatus_t *pxTaskStatusArray = NULL;
		volatile UBaseType_t uxArraySize, x;
		UBaseType_t uxCurrentNumberOfTasks;
		uint32_t ulTotalTime;
		char cStatus;
		
		uxCurrentNumberOfTasks = uxTaskGetNumberOfTasks();

		/* Take a snapshot of the number of tasks in case it changes while this
		function is executing. */
		uxArraySize = uxCurrentNumberOfTasks;

		/* Allocate an array index for each task. */
		pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) );

		if( pxTaskStatusArray != NULL )
		{
			/* Generate the (binary) data. */
			uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, &ulTotalTime );
			
			/* For percentage calculations. */
			ulTotalTime /= 100UL;
			
			/* Create a human readable table from the binary data. */
			for( x = 0; x < uxArraySize; x++ )
			{
				switch( pxTaskStatusArray[ x ].eCurrentState )
				{
					case eReady:		//tskREADY_CHAR;
						cStatus = 'R'; 
						break;
					case eBlocked:		//tskBLOCKED_CHAR;
						cStatus = 'B'; 
						break;
					case eSuspended:	//tskSUSPENDED_CHAR;
						cStatus = 'S'; 
						break;
					case eDeleted:		//tskDELETED_CHAR;
						cStatus = 'D'; 
						break;
					default:			/* Should not get here, but it is included to prevent static checking errors. */
						cStatus = ' ';
						break;
				}
				task_sta[x]->task_handle = pxTaskStatusArray[x].xHandle;

				strncpy(task_sta[x]->name, pxTaskStatusArray[x].pcTaskName, OS_NAME_SIZE);
				
				task_sta[x]->status = cStatus;
				task_sta[x]->prio =  pxTaskStatusArray[x].uxCurrentPriority;
				task_sta[x]->free_stk = pxTaskStatusArray[x].usStackHighWaterMark;
				task_sta[x]->id = pxTaskStatusArray[x].xTaskNumber;

#if (configGENERATE_RUN_TIME_STATS == 1)
				{
					uint32_t ulStatsAsPercentage;
					
					task_sta[x]->run_time = pxTaskStatusArray[ x ]->ulRunTimeCounter;
				
					ulStatsAsPercentage = pxTaskStatusArray[ x ]->ulRunTimeCounter / ulTotalTime;
					if( ulStatsAsPercentage > 0UL )
					{
						task_sta[x]->usage = ulStatsAsPercentage;
					}
					else
					{
						task_sta[x]->usage = 0;
					}
				}
#else
				task_sta[x]->run_time = -1;
				task_sta[x]->usage = -1;
#endif
			}
			vPortFree( pxTaskStatusArray ); /* Free the array */
		}
	}
	os_critical_exit();			//退出临界区

#endif
	return OS_STA_SUCCESS;
}

#endif

#endif // CONFIG_OS_ENABLE

